From 97e3ccc58b2fab663ec40b49464b528f2bf6fbf7 Mon Sep 17 00:00:00 2001 From: Tristan Van Berkom Date: Tue, 26 Oct 2010 18:22:59 +0900 Subject: [PATCH] Added GtkCellAreaBox subclass to handle alignments of cells across rows inside a GtkCellAreaBox. --- gtk/Makefile.am | 2 + gtk/gtkcellareabox.c | 8 +- gtk/gtkcellareaboxiter.c | 378 +++++++++++++++++++++++++++++++++++++++ gtk/gtkcellareaboxiter.h | 111 ++++++++++++ gtk/gtkcellareaiter.c | 2 - 5 files changed, 497 insertions(+), 4 deletions(-) create mode 100644 gtk/gtkcellareaboxiter.c create mode 100644 gtk/gtkcellareaboxiter.h diff --git a/gtk/Makefile.am b/gtk/Makefile.am index dd5c6e478a..ab7f6f9115 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -170,6 +170,7 @@ gtk_public_h_sources = \ gtkcalendar.h \ gtkcellarea.h \ gtkcellareabox.h \ + gtkcellareaboxiter.h \ gtkcellareaiter.h \ gtkcelleditable.h \ gtkcelllayout.h \ @@ -435,6 +436,7 @@ gtk_base_c_sources = \ gtkcalendar.c \ gtkcellarea.c \ gtkcellareabox.c \ + gtkcellareaboxiter.c \ gtkcellareaiter.c \ gtkcelleditable.c \ gtkcelllayout.c \ diff --git a/gtk/gtkcellareabox.c b/gtk/gtkcellareabox.c index 059dbf9e07..ad4dcfa7ec 100644 --- a/gtk/gtkcellareabox.c +++ b/gtk/gtkcellareabox.c @@ -24,6 +24,7 @@ #include "gtkorientable.h" #include "gtkcelllayout.h" #include "gtkcellareabox.h" +#include "gtkcellareaboxiter.h" /* GObjectClass */ static void gtk_cell_area_box_finalize (GObject *object); @@ -311,7 +312,7 @@ gtk_cell_area_box_render (GtkCellArea *area, static GtkCellAreaIter * gtk_cell_area_box_create_iter (GtkCellArea *area) { - return NULL; + return (GtkCellAreaIter *)g_object_new (GTK_TYPE_CELL_AREA_BOX_ITER, NULL); } static GtkSizeRequestMode @@ -332,7 +333,7 @@ gtk_cell_area_box_get_preferred_width (GtkCellArea *area, gint *minimum_width, gint *natural_width) { - + g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (iter)); } static void @@ -342,6 +343,7 @@ gtk_cell_area_box_get_preferred_height (GtkCellArea *area, gint *minimum_height, gint *natural_height) { + g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (iter)); } @@ -354,6 +356,7 @@ gtk_cell_area_box_get_preferred_height_for_width (GtkCellArea *area, gint *minimum_height, gint *natural_height) { + g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (iter)); } @@ -365,6 +368,7 @@ gtk_cell_area_box_get_preferred_width_for_height (GtkCellArea *area, gint *minimum_width, gint *natural_width) { + g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (iter)); } diff --git a/gtk/gtkcellareaboxiter.c b/gtk/gtkcellareaboxiter.c new file mode 100644 index 0000000000..f0c79746a0 --- /dev/null +++ b/gtk/gtkcellareaboxiter.c @@ -0,0 +1,378 @@ +/* gtkcellareaboxiter.c + * + * Copyright (C) 2010 Openismus GmbH + * + * Authors: + * Tristan Van Berkom + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "gtkintl.h" +#include "gtkcellareaboxiter.h" + +/* GObjectClass */ +static void gtk_cell_area_box_iter_finalize (GObject *object); + +/* GtkCellAreaIterClass */ +static void gtk_cell_area_box_iter_flush_preferred_width (GtkCellAreaIter *iter); +static void gtk_cell_area_box_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter, + gint width); +static void gtk_cell_area_box_iter_flush_preferred_height (GtkCellAreaIter *iter); +static void gtk_cell_area_box_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter, + gint height); + +/* CachedSize management */ +typedef struct { + gint min_size; + gint nat_size; +} CachedSize; + +static CachedSize *cached_size_new (gint min_size, gint nat_size); +static void cached_size_free (CachedSize *size); + +struct _GtkCellAreaBoxIterPrivate +{ + /* Table of per renderer CachedSizes */ + GHashTable *base_widths; + GHashTable *base_heights; + + /* Table of per height/width hash tables of per renderer CachedSizes */ + GHashTable *widths; + GHashTable *heights; +}; + +G_DEFINE_TYPE (GtkCellAreaBoxIter, gtk_cell_area_box_iter, GTK_TYPE_CELL_AREA_ITER); + +static void +gtk_cell_area_box_iter_init (GtkCellAreaBoxIter *box_iter) +{ + GtkCellAreaBoxIterPrivate *priv; + + box_iter->priv = G_TYPE_INSTANCE_GET_PRIVATE (box_iter, + GTK_TYPE_CELL_AREA_BOX_ITER, + GtkCellAreaBoxIterPrivate); + priv = box_iter->priv; + + priv->base_widths = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify)cached_size_free); + priv->base_heights = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify)cached_size_free); + + priv->widths = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify)g_hash_table_destroy); + priv->heights = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify)g_hash_table_destroy); +} + +static void +gtk_cell_area_box_iter_class_init (GtkCellAreaBoxIterClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkCellAreaIterClass *iter_class = GTK_CELL_AREA_ITER_CLASS (class); + + /* GObjectClass */ + object_class->finalize = gtk_cell_area_box_iter_finalize; + + iter_class->flush_preferred_width = gtk_cell_area_box_iter_flush_preferred_width; + iter_class->flush_preferred_height_for_width = gtk_cell_area_box_iter_flush_preferred_height_for_width; + iter_class->flush_preferred_height = gtk_cell_area_box_iter_flush_preferred_height; + iter_class->flush_preferred_width_for_height = gtk_cell_area_box_iter_flush_preferred_width_for_height; + + g_type_class_add_private (object_class, sizeof (GtkCellAreaBoxIterPrivate)); +} + +/************************************************************* + * Cached Sizes * + *************************************************************/ +static CachedSize * +cached_size_new (gint min_size, + gint nat_size) +{ + CachedSize *size = g_slice_new (CachedSize); + + size->min_size = min_size; + size->nat_size = nat_size; + + return size; +} + +static void +cached_size_free (CachedSize *size) +{ + g_slice_free (CachedSize, size); +} + +/************************************************************* + * GObjectClass * + *************************************************************/ +static void +gtk_cell_area_box_iter_finalize (GObject *object) +{ + GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (object); + GtkCellAreaBoxIterPrivate *priv = box_iter->priv; + + g_hash_table_destroy (priv->base_widths); + g_hash_table_destroy (priv->base_heights); + g_hash_table_destroy (priv->widths); + g_hash_table_destroy (priv->heights); + + G_OBJECT_CLASS (gtk_cell_area_box_iter_parent_class)->finalize (object); +} + +/************************************************************* + * GtkCellAreaIterClass * + *************************************************************/ +static void +gtk_cell_area_box_iter_flush_preferred_width (GtkCellAreaIter *iter) +{ + GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter); + GtkCellAreaBoxIterPrivate *priv = box_iter->priv; + + g_hash_table_remove_all (priv->base_widths); + + GTK_CELL_AREA_ITER_GET_CLASS + (gtk_cell_area_box_iter_parent_class)->flush_preferred_width (iter); +} + +static void +gtk_cell_area_box_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter, + gint width) +{ + GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter); + GtkCellAreaBoxIterPrivate *priv = box_iter->priv; + + /* Flush all sizes for special -1 value */ + if (width < 0) + g_hash_table_remove_all (priv->heights); + else + g_hash_table_remove (priv->heights, GINT_TO_POINTER (width)); + + GTK_CELL_AREA_ITER_GET_CLASS + (gtk_cell_area_box_iter_parent_class)->flush_preferred_height_for_width (iter, width); +} + +static void +gtk_cell_area_box_iter_flush_preferred_height (GtkCellAreaIter *iter) +{ + GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter); + GtkCellAreaBoxIterPrivate *priv = box_iter->priv; + + g_hash_table_remove_all (priv->base_heights); + + GTK_CELL_AREA_ITER_GET_CLASS + (gtk_cell_area_box_iter_parent_class)->flush_preferred_height (iter); +} + +static void +gtk_cell_area_box_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter, + gint height) +{ + GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter); + GtkCellAreaBoxIterPrivate *priv = box_iter->priv; + + /* Flush all sizes for special -1 value */ + if (height < 0) + g_hash_table_remove_all (priv->widths); + else + g_hash_table_remove (priv->widths, GINT_TO_POINTER (height)); + + GTK_CELL_AREA_ITER_GET_CLASS + (gtk_cell_area_box_iter_parent_class)->flush_preferred_width_for_height (iter, height); +} + +/************************************************************* + * API * + *************************************************************/ + +void +gtk_cell_area_box_push_cell_width (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint minimum_width, + gint natural_width) +{ + GtkCellAreaBoxIterPrivate *priv; + CachedSize *size; + + g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + + priv = box_iter->priv; + size = g_hash_table_lookup (priv->base_widths, renderer); + + if (!size) + { + size = cached_size_new (minimum_width, natural_width); + g_hash_table_insert (priv->base_widths, renderer, size); + } + else + { + size->min_size = MAX (size->min_size, minimum_width); + size->nat_size = MAX (size->nat_size, natural_width); + } +} + +void +gtk_cell_area_box_push_cell_height_for_width (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint for_width, + gint minimum_height, + gint natural_height) +{ + GtkCellAreaBoxIterPrivate *priv; + GHashTable *cell_table; + CachedSize *size; + + g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + + priv = box_iter->priv; + cell_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width)); + + if (!cell_table) + { + cell_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify)cached_size_free); + + g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), cell_table); + } + + size = g_hash_table_lookup (cell_table, renderer); + + if (!size) + { + size = cached_size_new (minimum_height, natural_height); + g_hash_table_insert (cell_table, renderer, size); + } + else + { + size->min_size = MAX (size->min_size, minimum_height); + size->nat_size = MAX (size->nat_size, natural_height); + } +} + +void +gtk_cell_area_box_push_cell_height (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint minimum_height, + gint natural_height) +{ + GtkCellAreaBoxIterPrivate *priv; + CachedSize *size; + + g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + + priv = box_iter->priv; + size = g_hash_table_lookup (priv->base_heights, renderer); + + if (!size) + { + size = cached_size_new (minimum_height, natural_height); + g_hash_table_insert (priv->base_widths, renderer, size); + } + else + { + size->min_size = MAX (size->min_size, minimum_height); + size->nat_size = MAX (size->nat_size, natural_height); + } +} + +void +gtk_cell_area_box_push_cell_width_for_height (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint for_height, + gint minimum_width, + gint natural_width) +{ + GtkCellAreaBoxIterPrivate *priv; + GHashTable *cell_table; + CachedSize *size; + + g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + + priv = box_iter->priv; + cell_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height)); + + if (!cell_table) + { + cell_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify)cached_size_free); + + g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), cell_table); + } + + size = g_hash_table_lookup (cell_table, renderer); + + if (!size) + { + size = cached_size_new (minimum_width, natural_width); + g_hash_table_insert (cell_table, renderer, size); + } + else + { + size->min_size = MAX (size->min_size, minimum_width); + size->nat_size = MAX (size->nat_size, natural_width); + } +} + +void +gtk_cell_area_box_get_cell_width (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint *minimum_width, + gint *natural_width) +{ + g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + +} + +void +gtk_cell_area_box_get_cell_height_for_width (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint for_width, + gint *minimum_height, + gint *natural_height) +{ + g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + +} + +void +gtk_cell_area_box_get_cell_height (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint minimum_height, + gint natural_height) +{ + g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + +} + +void +gtk_cell_area_box_get_cell_width_for_height (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint for_height, + gint *minimum_width, + gint *natural_width) +{ + g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); + g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); + +} diff --git a/gtk/gtkcellareaboxiter.h b/gtk/gtkcellareaboxiter.h new file mode 100644 index 0000000000..36f25bea5a --- /dev/null +++ b/gtk/gtkcellareaboxiter.h @@ -0,0 +1,111 @@ +/* gtkcellareaboxiter.h + * + * Copyright (C) 2010 Openismus GmbH + * + * Authors: + * Tristan Van Berkom + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __GTK_CELL_AREA_BOX_ITER_H__ +#define __GTK_CELL_AREA_BOX_ITER_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_CELL_AREA_BOX_ITER (gtk_cell_area_box_iter_get_type ()) +#define GTK_CELL_AREA_BOX_ITER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_AREA_BOX_ITER, GtkCellAreaBoxIter)) +#define GTK_CELL_AREA_BOX_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_CELL_AREA_BOX_ITER, GtkCellAreaBoxIterClass)) +#define GTK_IS_CELL_AREA_BOX_ITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_AREA_BOX_ITER)) +#define GTK_IS_CELL_AREA_BOX_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CELL_AREA_BOX_ITER)) +#define GTK_CELL_AREA_BOX_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CELL_AREA_BOX_ITER, GtkCellAreaBoxIterClass)) + +typedef struct _GtkCellAreaBoxIter GtkCellAreaBoxIter; +typedef struct _GtkCellAreaBoxIterClass GtkCellAreaBoxIterClass; +typedef struct _GtkCellAreaBoxIterPrivate GtkCellAreaBoxIterPrivate; + +struct _GtkCellAreaBoxIter +{ + GtkCellAreaIter parent_instance; + + GtkCellAreaBoxIterPrivate *priv; +}; + +struct _GtkCellAreaBoxIterClass +{ + GtkCellAreaIterClass parent_class; + +}; + +GType gtk_cell_area_box_iter_get_type (void) G_GNUC_CONST; + + +/* Update cell alignments */ +void gtk_cell_area_box_push_cell_width (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint minimum_width, + gint natural_width); + +void gtk_cell_area_box_push_cell_height_for_width (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint for_width, + gint minimum_height, + gint natural_height); + +void gtk_cell_area_box_push_cell_height (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint minimum_height, + gint natural_height); + +void gtk_cell_area_box_push_cell_width_for_height (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint for_height, + gint minimum_width, + gint natural_width); + +/* Fetch cell alignments */ +void gtk_cell_area_box_get_cell_width (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint *minimum_width, + gint *natural_width); + +void gtk_cell_area_box_get_cell_height_for_width (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint for_width, + gint *minimum_height, + gint *natural_height); + +void gtk_cell_area_box_get_cell_height (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint minimum_height, + gint natural_height); + +void gtk_cell_area_box_get_cell_width_for_height (GtkCellAreaBoxIter *box_iter, + GtkCellRenderer *renderer, + gint for_height, + gint *minimum_width, + gint *natural_width); + +G_END_DECLS + +#endif /* __GTK_CELL_AREA_BOX_ITER_H__ */ diff --git a/gtk/gtkcellareaiter.c b/gtk/gtkcellareaiter.c index 1c69a3003c..d4de66b239 100644 --- a/gtk/gtkcellareaiter.c +++ b/gtk/gtkcellareaiter.c @@ -24,8 +24,6 @@ #include "config.h" #include "gtkintl.h" #include "gtkmarshalers.h" -#include "gtkorientable.h" -#include "gtkcelllayout.h" #include "gtkcellareaiter.h" /* GObjectClass */ -- 2.30.2